/*
 * Copyright 2022-2029 heshuixing(https://gitee.com/heshuixing)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mercury.ec.module.air.controller.admin.callback.sunstn;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mercury.ec.framework.air.core.client.dto.search.detr.AirDetrReqDTO;
import com.mercury.ec.framework.air.core.client.dto.search.detr.AirDetrRespDTO;
import com.mercury.ec.framework.air.core.client.dto.search.detr.AirDetrRouteRespDTO;
import com.mercury.ec.framework.air.core.client.dto.search.rt.*;
import com.mercury.ec.framework.air.core.client.dto.search.rtkt.AirRtktReqDTO;
import com.mercury.ec.framework.air.core.client.dto.search.rtkt.AirRtktRespDTO;
import com.mercury.ec.framework.air.core.client.impl.sunstn.util.SunstnUtils;
import com.mercury.ec.framework.common.enums.ClientTypeEnum;
import com.mercury.ec.framework.common.enums.ProductTypeEnum;
import com.mercury.ec.framework.common.exception.ServiceException;
import com.mercury.ec.framework.common.util.object.BeanUtils;
import com.mercury.ec.framework.datapermission.core.annotation.DataPermission;
import com.mercury.ec.framework.dict.core.DictFrameworkUtils;
import com.mercury.ec.framework.tenant.core.util.TenantUtils;
import com.mercury.ec.module.air.controller.admin.callback.sunstn.vo.SunstnCallbackReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.order.AirOrderCreateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.order.AirOrderIssuedReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.order.AirOrderRespVO;
import com.mercury.ec.module.air.controller.admin.order.vo.order.AirOrderUpdateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderpassenger.AirOrderPassengerCreateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderpassenger.AirOrderPassengerRespVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderpassenger.AirOrderPassengerUpdateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderprice.AirOrderPriceCreateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderprice.AirOrderPriceIssuedReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderprice.AirOrderPriceRespVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderprice.AirOrderPriceUpdateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderroute.AirOrderRouteCreateReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderroute.AirOrderRouteIssuedReqVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderroute.AirOrderRouteRespVO;
import com.mercury.ec.module.air.controller.admin.order.vo.orderroute.AirOrderRouteUpdateReqVO;
import com.mercury.ec.module.air.enums.*;
import com.mercury.ec.module.air.service.api.AirApiService;
import com.mercury.ec.module.air.service.order.AirOrderService;
import com.mercury.ec.module.basic.controller.admin.airservicefeerule.vo.rule.AirServiceFeeRuleRespVO;
import com.mercury.ec.module.basic.controller.admin.airservicefeerule.vo.rulesetting.AirServiceFeeRuleSettingRespVO;
import com.mercury.ec.module.basic.controller.admin.airservicefeerule.vo.rulesetting.AirServiceFeeRuleSettingTripTypeRespVO;
import com.mercury.ec.module.basic.controller.admin.channel.vo.channel.ChannelRespVO;
import com.mercury.ec.module.basic.controller.admin.customer.vo.CustomerRespVO;
import com.mercury.ec.module.basic.controller.admin.customerproductsetting.vo.CustomerProductSettingRespVO;
import com.mercury.ec.module.basic.controller.admin.passenger.vo.passenger.PassengerRespVO;
import com.mercury.ec.module.basic.dal.dataobject.vendor.VendorDO;
import com.mercury.ec.module.basic.enums.BasicAirChannelTypeEnum;
import com.mercury.ec.module.basic.enums.BasicAirTicketTypeEnum;
import com.mercury.ec.module.basic.enums.BasicBizScopeTypeEnum;
import com.mercury.ec.module.basic.service.airport.AirportService;
import com.mercury.ec.module.basic.service.channel.ChannelService;
import com.mercury.ec.module.basic.service.customer.CustomerService;
import com.mercury.ec.module.basic.service.passenger.PassengerService;
import com.mercury.ec.module.basic.service.vendor.VendorService;
import com.mercury.ec.module.system.dal.dataobject.tenant.TenantDO;
import com.mercury.ec.module.system.dal.dataobject.user.AdminUserDO;
import com.mercury.ec.module.system.service.tenant.TenantService;
import com.mercury.ec.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新港黑屏回调
 *
 * @author hesx
 */
@Tag(name = "管理后台 - 机票订单 - 新港回调")
@Slf4j
@RestController
@RequestMapping("/air/callback/sunstn")
@Validated
public class SunstnCallbackController {

    @Resource
    private TenantService tenantService;
    @Resource
    private AirOrderService airOrderService;
    @Resource
    private AirportService airportService;
    @Resource
    private CustomerService customerService;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private PassengerService passengerService;
    @Resource
    private ChannelService channelService;
    @Resource
    private VendorService vendorService;
    @Resource
    private AirApiService airApiService;


    /**
     * 新港sd回调
     * http://8.134.103.20:3008/admin-api/air/callback/sunstn/sd/1/CAN180
     *
     * @param tenantId 租户
     * @param reqVO
     * @return
     */
    @GetMapping(value = {"/sd/{tenantId}", "/sd/{tenantId}/{officeNo}"})
    @Operation(summary = "sd回调")
    @DataPermission(enable = false)
    public String sd(@PathVariable("tenantId") Long tenantId, @PathVariable(value = "officeNo", required = false) String officeNo, SunstnCallbackReqVO reqVO) {
        log.info("机票订单新港sd回调，租户【{}】原始参数：{}", tenantId, JSONUtil.toJsonPrettyStr(reqVO));
        TenantDO tenant = tenantService.getTenant(tenantId);
        if (tenant == null) {
            log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】租户不存在，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
            return "Success";
        }
        // 校验
        if (!"booking".equalsIgnoreCase(reqVO.getMode())) {
            log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】非预订指令【{}】，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, reqVO.getMode());
            return "Success"; // 返回成功，防止重复回调浪费流量
        }
        AdminUserDO user = TenantUtils.execute(tenantId, () -> adminUserService.getUserByEtermUsername(reqVO.getWorkno()));
        if (user == null) {
            ChannelRespVO channel = TenantUtils.execute(tenantId, () -> channelService.getChannelByChannelTypeAndType(ProductTypeEnum.AIR.getType(), BasicAirChannelTypeEnum.BSP.getType(), BasicAirTicketTypeEnum.BSP.getType()));
            if (channel == null || channel.getIssueUserId() == null) {
                log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】订座员不存在，且未在渠道维护订座员，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
                return "Success";
            }
            user = TenantUtils.execute(tenantId, () -> adminUserService.getUser(channel.getIssueUserId()));
        }

        if ("cancel".equalsIgnoreCase(reqVO.getAction())) {
            // 取消订单
            log.info("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】指令【{}】，开始取消订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, reqVO.getAction());
            try {
                AdminUserDO finalUser = user;
                TenantUtils.execute(tenantId, () -> airOrderService.cancelOrderByPnr(finalUser.getId(), reqVO.getPnr()));
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】取消订单异常【{}】", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e.getCause().getMessage());
                } else {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】取消订单异常", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e);
                }
            }
        } else {
            log.info("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】指令【{}】，开始生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, reqVO.getAction());
            // 编码提取
            AirRtReqDTO airRtReqDTO = new AirRtReqDTO();
            airRtReqDTO.setPnr(reqVO.getPnr());
            airRtReqDTO.setOfficeNo(officeNo);
            airRtReqDTO.setScopeType(BasicBizScopeTypeEnum.DOMESTIC.getType());
            AirRtRespDTO rtResult = null;
            Boolean isInternation = false;
            try {
                rtResult = TenantUtils.execute(tenantId, () -> airApiService.rt(airRtReqDTO));
                // 根据行程判断是否国际，含国际航段则再调国际RT接口
                List<String> airportNos = new ArrayList<>();
                airportNos.addAll(rtResult.getRoutes().stream().map(p -> p.getDepart()).collect(Collectors.toList()));
                airportNos.addAll(rtResult.getRoutes().stream().map(p -> p.getArrive()).collect(Collectors.toList()));
                // 排除香港、澳门，新港接口按国际查询会导致证件号缺失，信息不全
                airportNos.remove("HKG");
                airportNos.remove("MFM");
                isInternation = TenantUtils.execute(tenantId, () -> airportService.isInternation(airportNos));
                if (isInternation) {
                    rtResult = TenantUtils.execute(tenantId, () -> airApiService.rt(airRtReqDTO));
                    airRtReqDTO.setScopeType(BasicBizScopeTypeEnum.INTERNATIONAL.getType());
                }
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RT接口异常【{}】，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e.getCause().getMessage());
                } else {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RT接口异常，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e);
                }
                return "Success";
            }
            // 如果已有票号，不处理
            long ticketNoCount = rtResult.getPassengers().stream().filter(p -> StrUtil.isNotBlank(p.getTicketNo())).count();
            if (ticketNoCount > 0) {
                log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】已有票号，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
                return "Success";
            }

            // 解析RMK中的客户
            String customerNo = SunstnUtils.getCustomerNo(rtResult.getRemark());
//            log.info("新港sd回调RT编码【{}】解析客户编号：{}", reqVO.getPnr(), customerNo);
//            if (StrUtil.isBlank(customerNo)) {
//                log.error("机票订单新港sd回调，编码【{}】RMK项客户编号不存在，停止生成订单", reqVO.getPnr());
//                return "Success";
//            }
            CustomerRespVO customer = null;
            if (StrUtil.isBlank(customerNo)) {
                // 导入渠道设置漏单补单客户
                ChannelRespVO channel = TenantUtils.execute(tenantId, () -> channelService.getChannelByChannelTypeAndType(ProductTypeEnum.AIR.getType(), BasicAirChannelTypeEnum.BSP.getType(), BasicAirTicketTypeEnum.BSP.getType()));
                if (channel == null || channel.getLoseOrderCustomerId() == null) {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RMK项客户编号不存在，且未在渠道维护漏单补单客户，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
                    return "Success";
                }
                customer = TenantUtils.execute(tenantId, () -> customerService.getCustomer(channel.getLoseOrderCustomerId()));
            } else {
                String finalCustomerNo = customerNo;
                customer = TenantUtils.execute(tenantId, () -> customerService.getCustomerByNo(finalCustomerNo));
            }
            if (customer == null) {
                log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RMK客户【{}】不存在，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo);
                return "Success";
            }
            customerNo = customer.getNo();
            // 解析RMK中的联系人
            String contactNo = SunstnUtils.getContactNo(rtResult.getRemark());
            PassengerRespVO contactPassenger = null;
            if (StrUtil.isNotBlank(contactNo)) {
                contactPassenger = TenantUtils.execute(tenantId, () -> passengerService.getPassengerByNo(contactNo));
            }

            // 产品设置
//            if (CollUtil.isEmpty(customer.getProductSettings()) || customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).collect(Collectors.toList()).size() == 0) {
//                log.error("机票订单新港sd回调，编码【{}】客户【{}】机票产品设置不存在，停止生成订单", reqVO.getPnr(), customerNo);
//                return "Success";
//            }
            CustomerProductSettingRespVO customerProductSetting = null;
            if (CollUtil.isNotEmpty(customer.getProductSettings()) && customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).collect(Collectors.toList()).size() > 0) {
                customerProductSetting = customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).findFirst().get();
            }

            // 根据编码获取订单
            AirOrderRespVO order = TenantUtils.execute(tenantId, () -> airOrderService.getOrderByPnr(reqVO.getPnr()));
            if (order == null) {
                // 生成订单
                try {
                    Long orderId = createOrder(tenantId, customer, user, isInternation, rtResult, customerProductSetting, contactPassenger);
                    TenantUtils.execute(tenantId, () -> airOrderService.getOrder(orderId));
                } catch (Exception e) {
                    if (e.getCause() instanceof ServiceException) {
                        log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，生成订单异常【{}】", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e.getCause().getMessage());
                    } else {
                        log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，生成订单异常", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e);
                    }
                }
            } else {
                if (AirOrderStatusEnum.isIssued(order.getStatus())) {
                    log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，订单已出票，停止更新订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo);
                    return "Success";
                }
                // 更新订单
                AirOrderUpdateReqVO airOrderUpdateReqVO = BeanUtils.toBean(order, AirOrderUpdateReqVO.class);
                airOrderUpdateReqVO.setPnrContent(rtResult.getPnrContent());
                airOrderUpdateReqVO.setNeedInvoice(customerProductSetting != null ? customerProductSetting.getNeedInvoice() : false);
                airOrderUpdateReqVO.setMakeInvoiceType(customerProductSetting != null ? customerProductSetting.getMakeInvoiceType() : null);
                airOrderUpdateReqVO.setInvoiceType(customerProductSetting != null ? customerProductSetting.getMakeInvoiceType() : null);
                airOrderUpdateReqVO.setDeliveryType(customerProductSetting != null ? customerProductSetting.getDeliveryType() : null);
                airOrderUpdateReqVO.setSalePaySubjectId(customer.getPaySubjectId());
                airOrderUpdateReqVO.setContact(contactPassenger == null ? customer.getContact() : contactPassenger.getName());
                airOrderUpdateReqVO.setContactPhone(contactPassenger == null ? customer.getContactPhone() : contactPassenger.getMobile());
                airOrderUpdateReqVO.setContactMobile(contactPassenger == null ? customer.getContactMobile() : contactPassenger.getMobile());
                airOrderUpdateReqVO.setContactEmail(contactPassenger == null ? customer.getContactEmail() : contactPassenger.getEmail());
//                airOrderUpdateReqVO.setRemark(rtResult.getRemark());

                // 更新行程
                List<AirOrderRouteUpdateReqVO> routes = new ArrayList<>();
                int routeSerialNo = 1;
                for (AirRtRouteRespDTO airRtRouteRespDTO : rtResult.getRoutes()) {
                    AirOrderRouteUpdateReqVO route = new AirOrderRouteUpdateReqVO();
                    route.setSerialNo(routeSerialNo);
                    route.setOriginOrderRouteId(null);
                    route.setAirlineNo(airRtRouteRespDTO.getAirlineNo());
                    route.setFlightNo(airRtRouteRespDTO.getFlightNo());
                    route.setCabin(airRtRouteRespDTO.getCabin());
                    route.setDepart(airRtRouteRespDTO.getDepart());
                    route.setArrive(airRtRouteRespDTO.getArrive());
                    route.setFlightDate(airRtRouteRespDTO.getFlightDate());
                    route.setDepartTime(airRtRouteRespDTO.getDepartTime());
                    route.setArriveTime(airRtRouteRespDTO.getArriveTime());
                    route.setDepartTerminal(airRtRouteRespDTO.getDepartTerminal());
                    route.setArriveTerminal(airRtRouteRespDTO.getArriveTerminal());
                    route.setFlightDays(airRtRouteRespDTO.getFlightDays());
                    route.setHaveFood(false);
                    route.setStop(false);
                    route.setShare(false);
                    route.setThrough(false);
                    route.setRouteStatus(airRtRouteRespDTO.getRouteStatus());
                    routes.add(route);
                    routeSerialNo++;
                }
                airOrderUpdateReqVO.setRoutes(routes);

                // 更新乘客
                List<AirOrderPassengerUpdateReqVO> passengers = new ArrayList<>();
                int passengerSerialNo = 1;
                for (AirRtPassengerRespDTO airRtPassengerRespDTO : rtResult.getPassengers()) {
                    AirOrderPassengerUpdateReqVO passenger = new AirOrderPassengerUpdateReqVO();
                    passenger.setSerialNo(passengerSerialNo);
                    passenger.setType(airRtPassengerRespDTO.getType());
                    passenger.setCountryNo(airRtPassengerRespDTO.getCountryNo());
                    passenger.setName(airRtPassengerRespDTO.getName());
                    passenger.setSex(airRtPassengerRespDTO.getSex());
                    passenger.setCardType(airRtPassengerRespDTO.getCardType());
                    passenger.setCardNo(airRtPassengerRespDTO.getCardNo());
                    passenger.setCardValidDate(airRtPassengerRespDTO.getCardValidDate());
                    passenger.setCardIssuingCountryNo(airRtPassengerRespDTO.getCardIssuingCountryNo());
                    passenger.setBirthday(airRtPassengerRespDTO.getBirthday());
                    passenger.setHaveBaby(airRtPassengerRespDTO.getHaveBaby());
                    passenger.setMobile(airRtPassengerRespDTO.getMobile());
                    passenger.setSendSms(false);
                    passengers.add(passenger);
                    passengerSerialNo++;
                }
                airOrderUpdateReqVO.setPassengers(passengers);

                // 更新价格
                // 机票服务费规则设置（默认取因公）
                AirServiceFeeRuleRespVO airServiceFeeRule = customer.getAirServiceFeeRule();
                AirServiceFeeRuleSettingTripTypeRespVO business = Optional.ofNullable(airServiceFeeRule).map(AirServiceFeeRuleRespVO::getBusiness).orElse(new AirServiceFeeRuleSettingTripTypeRespVO());
                AirServiceFeeRuleSettingRespVO airServiceFeeRuleSetting = isInternation ? business.getInternation() : business.getDomestic();
                // 初始默认0，兼容接口无价格
                AirRtPriceRespDTO lowestPrice = new AirRtPriceRespDTO();
                lowestPrice.setTicketPrice(BigDecimal.ZERO);
                lowestPrice.setAirportTax(BigDecimal.ZERO);
                lowestPrice.setOilTax(BigDecimal.ZERO);
                if (CollUtil.isNotEmpty(rtResult.getPrices())) {
                    rtResult.getPrices().sort(Comparator.comparing(p -> p.getTicketPrice()));
                    lowestPrice = rtResult.getPrices().get(0);
                }
                List<AirOrderPriceUpdateReqVO> prices = new ArrayList<>();
                for (AirOrderRouteUpdateReqVO route : routes) {
                    for (AirOrderPassengerUpdateReqVO passenger : passengers) {
                        AirOrderPriceCreateReqVO airOrderPriceCreateReqVO = getAirOrderPriceCreateReqVO();
                        airOrderPriceCreateReqVO.setRouteSerialNo(route.getSerialNo());
                        airOrderPriceCreateReqVO.setPassengerSerialNo(passenger.getSerialNo());
                        if (route.getSerialNo() == 1) {
                            // 价格写到第一航段
                            airOrderPriceCreateReqVO.setFareBasis(lowestPrice.getFareBasis());
                            // 销售
                            airOrderPriceCreateReqVO.setSaleTicketPrice(lowestPrice.getTicketPrice());
                            airOrderPriceCreateReqVO.setSalePrice(lowestPrice.getTicketPrice());
                            airOrderPriceCreateReqVO.setSaleAirportTax(lowestPrice.getAirportTax());
                            airOrderPriceCreateReqVO.setSaleOilTax(lowestPrice.getOilTax());
                            airOrderPriceCreateReqVO.setSaleTax(airOrderPriceCreateReqVO.getSaleAirportTax().add(airOrderPriceCreateReqVO.getSaleOilTax()));
                            airOrderPriceCreateReqVO.setSaleServiceFee(SunstnUtils.getSaleServiceFee(airServiceFeeRuleSetting, lowestPrice.getTicketPrice().add(lowestPrice.getAirportTax()).add(lowestPrice.getOilTax()), passenger.getType(), routes.size()));

                            // 采购
                            airOrderPriceCreateReqVO.setPurchaseTicketPrice(lowestPrice.getTicketPrice());
                            airOrderPriceCreateReqVO.setPurchasePrice(lowestPrice.getTicketPrice());
                            airOrderPriceCreateReqVO.setPurchaseAirportTax(lowestPrice.getAirportTax());
                            airOrderPriceCreateReqVO.setPurchaseOilTax(lowestPrice.getOilTax());
                            airOrderPriceCreateReqVO.setPurchaseTax(airOrderPriceCreateReqVO.getPurchaseAirportTax().add(airOrderPriceCreateReqVO.getPurchaseOilTax()));
                        }
                        prices.add(BeanUtils.toBean(airOrderPriceCreateReqVO, AirOrderPriceUpdateReqVO.class));
                    }
                }
                airOrderUpdateReqVO.setPrices(prices);
                try {
                    TenantUtils.execute(tenantId, () -> airOrderService.updateOrder(airOrderUpdateReqVO));
                } catch (Exception e) {
                    if (e.getCause() instanceof ServiceException) {
                        log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，更新订单异常【{}】", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e.getCause().getMessage());
                    } else {
                        log.error("机票订单新港sd回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，更新订单异常", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e);
                    }
                }
            }
        }
        return "Success";
    }

    /**
     * 新港etdz回调
     * http://8.134.103.20:3008/admin-api/air/callback/sunstn/etdz/1/CAN180
     *
     * @param tenantId 租户
     * @param reqVO
     * @return
     */
    @GetMapping(value = {"/etdz/{tenantId}", "/etdz/{tenantId}/{officeNo}"})
    @Operation(summary = "etdz回调")
    @DataPermission(enable = false)
    public String etdz(@PathVariable("tenantId") Long tenantId, @PathVariable(value = "officeNo", required = false) String officeNo, SunstnCallbackReqVO reqVO) {
        log.info("机票订单新港etdz回调，租户【{}】原始参数：{}", tenantId, JSONUtil.toJsonPrettyStr(reqVO));
        TenantDO tenant = tenantService.getTenant(tenantId);
        if (tenant == null) {
            log.error("机票订单新港etdz回调，租户【{}】账号【{}】编码【{}】office号【{}】租户不存在，停止出票", tenantId, reqVO.getWorkno(), reqVO.getPnr(), officeNo);
            return "Success";
        }
        // 校验
        if (!"etdz".equalsIgnoreCase(reqVO.getMode())) {
            log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】非出票指令【{}】，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, reqVO.getMode());
            return "Success"; // 返回成功，防止重复回调浪费流量
        }
        AdminUserDO user = TenantUtils.execute(tenantId, () -> adminUserService.getUserByEtermUsername(reqVO.getWorkno()));
        if (user == null) {
            ChannelRespVO channel = TenantUtils.execute(tenantId, () -> channelService.getChannelByChannelTypeAndType(ProductTypeEnum.AIR.getType(), BasicAirChannelTypeEnum.BSP.getType(), BasicAirTicketTypeEnum.BSP.getType()));
            if (channel == null || channel.getIssueUserId() == null) {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】订座员不存在，且未在渠道维护订座员，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
                return "Success";
            }
            user = TenantUtils.execute(tenantId, () -> adminUserService.getUser(channel.getIssueUserId()));
        }

        // 编码提取
        log.info("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】指令【{}】，开始出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, reqVO.getAction());
        AirRtReqDTO airRtReqDTO = new AirRtReqDTO();
        airRtReqDTO.setPnr(reqVO.getPnr());
        airRtReqDTO.setOfficeNo(officeNo);
        airRtReqDTO.setScopeType(BasicBizScopeTypeEnum.DOMESTIC.getType());
        AirRtRespDTO rtResult = null;
        Boolean isInternation = false;
        try {
            rtResult = TenantUtils.execute(tenantId, () -> airApiService.rt(airRtReqDTO));
            // 根据行程判断是否国际，含国际航段则再调国际RT接口
            List<String> airportNos = new ArrayList<>();
            airportNos.addAll(rtResult.getRoutes().stream().map(p -> p.getDepart()).collect(Collectors.toList()));
            airportNos.addAll(rtResult.getRoutes().stream().map(p -> p.getArrive()).collect(Collectors.toList()));
            // 排除香港、澳门，新港接口按国际查询会导致证件号缺失，信息不全
            airportNos.remove("HKG");
            airportNos.remove("MFM");
            isInternation = TenantUtils.execute(tenantId, () -> airportService.isInternation(airportNos));
            if (isInternation) {
                airRtReqDTO.setScopeType(BasicBizScopeTypeEnum.INTERNATIONAL.getType());
                rtResult = TenantUtils.execute(tenantId, () -> airApiService.rt(airRtReqDTO));
            }
        } catch (Exception e) {
            if (e.getCause() instanceof ServiceException) {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RT接口异常【{}】，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e.getCause().getMessage());
            } else {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RT接口异常，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, e);
            }
            return "Success";
        }
        // 解析RMK中的客户
        String customerNo = SunstnUtils.getCustomerNo(rtResult.getRemark());
//        log.info("新港etdz回调RT编码【{}】解析客户编号：{}", reqVO.getPnr(), customerNo);
//        if (StrUtil.isBlank(customerNo)) {
//            log.error("机票订单新港etdz回调，编码【{}】RMK项客户编号不存在，停止出票", reqVO.getPnr());
//            return "Success";
//        }
        CustomerRespVO customer = null;
        if (StrUtil.isBlank(customerNo)) {
            // 导入渠道设置漏单补单客户
            ChannelRespVO channel = TenantUtils.execute(tenantId, () -> channelService.getChannelByChannelTypeAndType(ProductTypeEnum.AIR.getType(), BasicAirChannelTypeEnum.BSP.getType(), BasicAirTicketTypeEnum.BSP.getType()));
            if (channel == null || channel.getLoseOrderCustomerId() == null) {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RMK项客户编号不存在，且未在渠道维护漏单补单客户，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo);
                return "Success";
            }
            customer = TenantUtils.execute(tenantId, () -> customerService.getCustomer(channel.getLoseOrderCustomerId()));
        } else {
            String finalCustomerNo = customerNo;
            customer = TenantUtils.execute(tenantId, () -> customerService.getCustomerByNo(finalCustomerNo));
        }
        if (customer == null) {
            log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】RMK客户【{}】不存在，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo);
            return "Success";
        }
        customerNo = customer.getNo();
        // 解析RMK中的联系人
        String contactNo = SunstnUtils.getContactNo(rtResult.getRemark());
        PassengerRespVO contactPassenger = null;
        if (StrUtil.isNotBlank(contactNo)) {
            contactPassenger = TenantUtils.execute(tenantId, () -> passengerService.getPassengerByNo(contactNo));
        }

        // 票号提取
        // 根据乘客类型detr获取价格
        List<AirRtPassengerRespDTO> rtPassengers = rtResult.getPassengers().stream().collect(Collectors.toMap(AirRtPassengerRespDTO::getType, v -> v, (v1, v2) -> v1)).values().stream().collect(Collectors.toList());
        Map<Integer, AirDetrRespDTO> detrResultMap = new HashMap<>();
        for (AirRtPassengerRespDTO rtPassenger : rtPassengers) {
            try {
                if (StrUtil.isBlank(rtPassenger.getTicketNo())) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】乘客【{}】无票号，跳过detr", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getName());
                    continue;
                }
                AirDetrReqDTO airDetrReqDTO = new AirDetrReqDTO();
                airDetrReqDTO.setOfficeNo(officeNo);
                airDetrReqDTO.setAirlineIssueNo(rtPassenger.getAirlineIssueNo());
                airDetrReqDTO.setTicketNo(rtPassenger.getTicketNo());
                airDetrReqDTO.setCardType(rtPassenger.getCardType());
                airDetrReqDTO.setCardNo(rtPassenger.getCardNo());
                AirDetrRespDTO detrResult = TenantUtils.execute(tenantId, () -> airApiService.detr(airDetrReqDTO));
                // detr有新票号，不处理
                if (StrUtil.isNotBlank(detrResult.getChangeTicketNo())) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】已有新票号【{}】，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, detrResult.getAirlineIssueNo() + detrResult.getTicketNo(), detrResult.getChangeAirlineIssueNo() + detrResult.getChangeTicketNo());
                    return "Success";
                }
                detrResultMap.put(rtPassenger.getType(), detrResult);
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】DETR接口异常【{}】，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getAirlineIssueNo() + rtPassenger.getTicketNo(), e.getCause().getMessage());
                } else {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】DETR接口异常，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getAirlineIssueNo() + rtPassenger.getTicketNo(), e);
                }
                return "Success";
            }
        }

        // RTKT提取
        // 根据乘客票号获取rtkt信息
        rtPassengers = rtResult.getPassengers().stream().collect(Collectors.toMap(AirRtPassengerRespDTO::getTicketNo, v -> v, (v1, v2) -> v1)).values().stream().collect(Collectors.toList());
        Map<String, AirRtktRespDTO> rtktResultMap = new HashMap<>();
        for (AirRtPassengerRespDTO rtPassenger : rtPassengers) {
            try {
                if (StrUtil.isBlank(rtPassenger.getTicketNo())) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】乘客【{}】无票号，跳过rtkt", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getName());
                    continue;
                }
                AirRtktReqDTO airRtktReqDTO = new AirRtktReqDTO();
                airRtktReqDTO.setOfficeNo(officeNo);
                airRtktReqDTO.setAirlineIssueNo(rtPassenger.getAirlineIssueNo());
                airRtktReqDTO.setTicketNo(rtPassenger.getTicketNo());
                AirRtktRespDTO rtktResult = TenantUtils.execute(tenantId, () -> airApiService.rtkt(airRtktReqDTO));
                if (rtktResult.getTicketType() == null) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】RTKT接口返回票证类型为空，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassengers.get(0).getAirlineIssueNo() + rtPassengers.get(0).getTicketNo());
                    return "Success";
                }
                rtktResultMap.put(rtPassenger.getAirlineIssueNo() + rtPassenger.getTicketNo(), rtktResult);
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】RTKT接口异常【{}】，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getAirlineIssueNo() + rtPassenger.getTicketNo(), e.getCause().getMessage());
                } else {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票号【{}】RTKT接口异常，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, rtPassenger.getAirlineIssueNo() + rtPassenger.getTicketNo(), e);
                }
                return "Success";
            }
        }

        // 产品设置
//        if (CollUtil.isEmpty(customer.getProductSettings()) || customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).collect(Collectors.toList()).size() == 0) {
//            log.error("机票订单新港etdz回调，编码【{}】客户【{}】机票产品设置不存在，停止出票", reqVO.getPnr(), customerNo);
//            return "Success";
//        }
        CustomerProductSettingRespVO customerProductSetting = null;
        if (CollUtil.isNotEmpty(customer.getProductSettings()) && customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).collect(Collectors.toList()).size() > 0) {
            customerProductSetting = customer.getProductSettings().stream().filter(p -> p.getProductType().equals(ProductTypeEnum.AIR.getType())).findFirst().get();
        }

        // 渠道设置-支付科目
        AirRtktRespDTO airRtktRespDTO = rtktResultMap.values().stream().findFirst().get();
        /**
         * 根据票证类型写死渠道类型查询渠道
         * 票证类型：BOP -> 渠道类型为 BOP / BSP -> 渠道类型为 BSP / 其他票证 -> BSP
         */
        int channelType = BasicAirChannelTypeEnum.BSP.getType();
        if (BasicAirTicketTypeEnum.isBop(airRtktRespDTO.getTicketType())) {
            channelType = BasicAirChannelTypeEnum.BOP.getType();
        } else if (BasicAirTicketTypeEnum.isUatp(airRtktRespDTO.getTicketType())) {
            channelType = BasicAirChannelTypeEnum.UATP.getType();
        }
        int finalChannelType = channelType;
        ChannelRespVO channel = TenantUtils.execute(tenantId, () -> channelService.getChannelByChannelTypeAndType(ProductTypeEnum.AIR.getType(), finalChannelType, airRtktRespDTO.getTicketType()));
        if (channel == null || channel.getPaySubjectId() == null) {
            log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】票证类型【{}】未维护出票支付科目，停止生成订单", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, DictFrameworkUtils.getDictDataLabel(BasicAirTicketTypeEnum.DICT_TYPE, airRtktRespDTO.getTicketType()));
            return "Success";
        }

        // 根据编码获取订单
        AirOrderRespVO order = TenantUtils.execute(tenantId, () -> airOrderService.getOrderByPnr(reqVO.getPnr()));
        if (order == null) {
            // 未生成订单则先生成订单
            try {
                Long orderId = createOrder(tenantId, customer, user, isInternation, rtResult, customerProductSetting, contactPassenger);
                order = TenantUtils.execute(tenantId, () -> airOrderService.getOrder(orderId));
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，订单出票补单异常【{}】", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e.getCause().getMessage());
                } else {
                    log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，订单出票补单异常", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e);
                }
                return "Success";
            }
        }

        // 极据出票office查询采购商
        String issueOffice = rtResult.getIssueOffice();
        VendorDO vendorDO = TenantUtils.execute(tenantId, () -> vendorService.getVendorByIssueOffice(issueOffice));
        if (vendorDO == null) {
            log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，未找到采购商，停止出票", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo);
            return "Success";
        }

        // 订单出票
        // 更新订单
        AirOrderIssuedReqVO airOrderIssuedReqVO = BeanUtils.toBean(order, AirOrderIssuedReqVO.class);
        airOrderIssuedReqVO.setPnrContent(rtResult.getPnrContent());
        airOrderIssuedReqVO.setNeedInvoice(customerProductSetting != null ? customerProductSetting.getNeedInvoice() : false);
        airOrderIssuedReqVO.setMakeInvoiceType(customerProductSetting != null ? customerProductSetting.getMakeInvoiceType() : null);
        airOrderIssuedReqVO.setInvoiceType(customerProductSetting != null ? customerProductSetting.getMakeInvoiceType() : null);
        airOrderIssuedReqVO.setDeliveryType(customerProductSetting != null ? customerProductSetting.getDeliveryType() : null);
        airOrderIssuedReqVO.setIssueUserId(user.getId());
        airOrderIssuedReqVO.setIssueTime(LocalDateTime.now());
        airOrderIssuedReqVO.setIssueOffice(issueOffice);
        airOrderIssuedReqVO.setSalePaySubjectId(customer.getPaySubjectId());
        airOrderIssuedReqVO.setPurchaseId(vendorDO.getId());
        airOrderIssuedReqVO.setPurchasePaySubjectId(channel.getPaySubjectId());
        airOrderIssuedReqVO.setContact(contactPassenger == null ? customer.getContact() : contactPassenger.getName());
        airOrderIssuedReqVO.setContactPhone(contactPassenger == null ? customer.getContactPhone() : contactPassenger.getMobile());
        airOrderIssuedReqVO.setContactMobile(contactPassenger == null ? customer.getContactMobile() : contactPassenger.getMobile());
        airOrderIssuedReqVO.setContactEmail(contactPassenger == null ? customer.getContactEmail() : contactPassenger.getEmail());
//        airOrderIssuedReqVO.setRemark(rtResult.getRemark());

        // 更新行程
        Map<String, AirRtRouteRespDTO> rtRouteMap = rtResult.getRoutes().stream().collect(Collectors.toMap(k -> k.getDepart() + k.getArrive(), v -> v, (v1, v2) -> v1));
        List<AirOrderRouteRespVO> routes = order.getRoutes();
        for (AirOrderRouteRespVO route : routes) {
            AirRtRouteRespDTO airRtRouteRespDTO = rtRouteMap.get(route.getDepart() + route.getArrive());
            if (airRtRouteRespDTO != null) {
                route.setRouteStatus(airRtRouteRespDTO.getRouteStatus());
            }
            // 更新行李额
            for (AirRtPassengerRespDTO rtPassenger : rtPassengers) {
                AirDetrRespDTO airDetrRespDTO = detrResultMap.get(rtPassenger.getType());
                if (airDetrRespDTO != null) {
                    Map<String, AirDetrRouteRespDTO> detrRouteMap = airDetrRespDTO.getRoutes().stream().collect(Collectors.toMap(k -> k.getDepart() + k.getArrive(), v -> v, (v1, v2) -> v1));
                    AirDetrRouteRespDTO airDetrRouteRespDTO = detrRouteMap.get(route.getDepart() + route.getArrive());
                    if (airDetrRouteRespDTO != null) {
                        route.setBaggageWeight(airDetrRouteRespDTO.getBaggageWeight());
                    }
                }
            }
        }
        airOrderIssuedReqVO.setRoutes(BeanUtils.toBean(routes, AirOrderRouteIssuedReqVO.class));

        // 更新票号
        Map<String, AirRtPassengerRespDTO> rtPassengerMap = rtResult.getPassengers().stream().collect(Collectors.toMap(k -> k.getCardType() + k.getCardNo(), v -> v, (v1, v2) -> v1));
        Map<Long, AirOrderPassengerRespVO> passengerMap = order.getPassengers().stream().collect(Collectors.toMap(k -> k.getId(), v -> v, (v1, v2) -> v1));
        for (AirOrderPriceRespVO price : order.getPrices()) {
            // 更新票号
            AirOrderPassengerRespVO airOrderPassengerRespVO = passengerMap.get(price.getOrderPassengerId());
            if (airOrderPassengerRespVO != null) {
                AirRtPassengerRespDTO airRtPassengerRespDTO = rtPassengerMap.get(airOrderPassengerRespVO.getCardType() + airOrderPassengerRespVO.getCardNo());
                if (airRtPassengerRespDTO != null) {
                    price.setAirlineIssueNo(airRtPassengerRespDTO.getAirlineIssueNo());
                    price.setTicketNo(airRtPassengerRespDTO.getTicketNo());
                    price.setTicketLastNo(airRtPassengerRespDTO.getTicketLastNo());
                }
                // 更新票证类型、票证状态
                AirDetrRespDTO airDetrRespDTO = detrResultMap.get(airOrderPassengerRespVO.getType());
                if (airDetrRespDTO != null && airDetrRespDTO.getTicketNo().equals(price.getTicketNo())) {
                    // 票证类型先取detr
                    airOrderIssuedReqVO.setTicketType(airDetrRespDTO.getTicketType());
                    price.setTicketStatus(airDetrRespDTO.getTicketStatus());
                }
                // 更新票价级别、打票机号
                AirRtktRespDTO rtktRespDTO = rtktResultMap.get(price.getAirlineIssueNo() + price.getTicketNo());
                if (rtktRespDTO != null) {
                    price.setFareBasis(rtktRespDTO.getFareBasis());
                    price.setTicketVendingMachineNo(rtktRespDTO.getTicketVendingMachineNo());
                    // 更新BOP票证类型（二次修正）
                    if (BasicAirTicketTypeEnum.isBop(rtktRespDTO.getTicketType())) {
                        airOrderIssuedReqVO.setTicketType(rtktRespDTO.getTicketType());
                    }
                }
            }
        }

        // 更新价格
        // 机票服务费规则设置（默认取因公）
        AirServiceFeeRuleRespVO airServiceFeeRule = customer.getAirServiceFeeRule();
        AirServiceFeeRuleSettingTripTypeRespVO business = Optional.ofNullable(airServiceFeeRule).map(AirServiceFeeRuleRespVO::getBusiness).orElse(new AirServiceFeeRuleSettingTripTypeRespVO());
        AirServiceFeeRuleSettingRespVO airServiceFeeRuleSetting = isInternation ? business.getInternation() : business.getDomestic();
        Map<Long, AirOrderRouteRespVO> routeMap = order.getRoutes().stream().collect(Collectors.toMap(k -> k.getId(), v -> v, (v1, v2) -> v1));
        for (AirOrderPriceRespVO price : order.getPrices()) {
            // 更新价格
            AirOrderRouteRespVO airOrderRouteRespVO = routeMap.get(price.getOrderRouteId());
            if (airOrderRouteRespVO != null) {
                if (airOrderRouteRespVO.getSerialNo() == 1) {
                    // 价格写到第一航段
                    AirOrderPassengerRespVO airOrderPassengerRespVO = passengerMap.get(price.getOrderPassengerId());
                    if (airOrderPassengerRespVO != null) {
                        AirRtPassengerRespDTO airRtPassengerRespDTO = rtPassengerMap.get(airOrderPassengerRespVO.getCardType() + airOrderPassengerRespVO.getCardNo());
                        if (airRtPassengerRespDTO != null) {
                            AirDetrRespDTO airDetrRespDTO = detrResultMap.get(airRtPassengerRespDTO.getType());
                            if (airDetrRespDTO != null) {
                                // 销售
                                price.setSaleTicketPrice(airDetrRespDTO.getTicketPrice());
                                price.setSalePrice(airDetrRespDTO.getTicketPrice());
                                price.setSaleAirportTax(airDetrRespDTO.getAirportTax());
                                price.setSaleOilTax(airDetrRespDTO.getOilTax());
                                price.setSaleTax(price.getSaleAirportTax().add(price.getSaleOilTax()));
                                price.setSaleServiceFee(SunstnUtils.getSaleServiceFee(airServiceFeeRuleSetting, airDetrRespDTO.getTicketPrice().add(airDetrRespDTO.getAirportTax()).add(airDetrRespDTO.getOilTax()), airOrderPassengerRespVO.getType(), routes.size()));

                                // 采购
                                price.setPurchaseTicketPrice(airDetrRespDTO.getTicketPrice());
                                price.setPurchasePrice(airDetrRespDTO.getTicketPrice());
                                price.setPurchaseAirportTax(airDetrRespDTO.getAirportTax());
                                price.setPurchaseOilTax(airDetrRespDTO.getOilTax());
                                price.setPurchaseTax(price.getPurchaseAirportTax().add(price.getPurchaseOilTax()));
                                // 采购代理费
                                AirRtktRespDTO rtktRespDTO = rtktResultMap.get(price.getAirlineIssueNo() + price.getTicketNo());
                                if (rtktRespDTO != null) {
                                    if (BasicBizScopeTypeEnum.isDomestic(order.getScopeType())) {
                                        price.setPurchaseAgencyFee(rtktRespDTO.getAgencyFee());
                                    } else if (BasicBizScopeTypeEnum.isInternational(order.getScopeType())) {
                                        price.setPurchaseAgencyFeeRate(rtktRespDTO.getAgencyFee().divide(BigDecimal.valueOf(100)));
                                        price.setPurchaseAgencyFee(price.getPurchaseTicketPrice().multiply(price.getPurchaseAgencyFeeRate()));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        // 重排价格行程、乘客序号
        List<AirOrderPriceIssuedReqVO> airOrderPriceIssuedReqVOS = new ArrayList<>();
        for (AirOrderRouteRespVO route : order.getRoutes()) {
            for (AirOrderPassengerRespVO passenger : order.getPassengers()) {
                for (AirOrderPriceRespVO price : order.getPrices()) {
                    if (price.getOrderRouteId().equals(route.getId()) && price.getOrderPassengerId().equals(passenger.getId())) {
                        AirOrderPriceIssuedReqVO airOrderPriceIssuedReqVO = BeanUtils.toBean(price, AirOrderPriceIssuedReqVO.class);
                        airOrderPriceIssuedReqVO.setRouteSerialNo(route.getSerialNo());
                        airOrderPriceIssuedReqVO.setPassengerSerialNo(passenger.getSerialNo());
                        airOrderPriceIssuedReqVOS.add(airOrderPriceIssuedReqVO);
                    }
                }
            }
        }
        airOrderIssuedReqVO.setPrices(airOrderPriceIssuedReqVOS);
        try {
            TenantUtils.execute(tenantId, () -> airOrderService.issuedOrder(airOrderIssuedReqVO));
        } catch (Exception e) {
            if (e.getCause() instanceof ServiceException) {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，订单出票异常【{}】", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e.getCause().getMessage());
            } else {
                log.error("机票订单新港etdz回调，租户【{}({})】账号【{}】编码【{}】office号【{}】客户【{}】，订单出票异常", tenantId, tenant.getName(), reqVO.getWorkno(), reqVO.getPnr(), officeNo, customerNo, e);
            }
        }
        return "Success";
    }

    /**
     * 生成订单
     *
     * @param tenantId
     * @param customer
     * @param user
     * @param isInternation
     * @param rtResult
     * @param customerProductSetting
     * @param contactPassenger
     * @return
     */
    private Long createOrder(Long tenantId,
                             CustomerRespVO customer,
                             AdminUserDO user,
                             Boolean isInternation,
                             AirRtRespDTO rtResult,
                             CustomerProductSettingRespVO customerProductSetting,
                             PassengerRespVO contactPassenger) {
        // 生成订单
        Long orderId = null;
        AirOrderCreateReqVO airOrderCreateReqVO = new AirOrderCreateReqVO();
        airOrderCreateReqVO.setSourceType(AirOrderSourceTypeEnum.ETERM.getType());
        airOrderCreateReqVO.setSourceNo(null);
//        airOrderCreateReqVO.setFinallyChangeType();
        airOrderCreateReqVO.setClientType(ClientTypeEnum.MIDDLE.getType());
        airOrderCreateReqVO.setType(AirOrderTypeEnum.SALE.getType());
        airOrderCreateReqVO.setOccupySeat(false);
//        airOrderCreateReqVO.setGroupNo();
        airOrderCreateReqVO.setScopeType(isInternation ? BasicBizScopeTypeEnum.INTERNATIONAL.getType() : BasicBizScopeTypeEnum.DOMESTIC.getType());
        airOrderCreateReqVO.setRouteType(rtResult.getRoutes().size() > 1 ? AirOrderRouteTypeEnum.DOUBLE_WAY.getType() : AirOrderRouteTypeEnum.ONE_WAY.getType());
        airOrderCreateReqVO.setPnr(rtResult.getPnr());
        airOrderCreateReqVO.setPnrStatus(rtResult.getPnrStatus());
        airOrderCreateReqVO.setPnrContent(rtResult.getPnrContent());
        airOrderCreateReqVO.setBigPnr(rtResult.getBigPnr());
        airOrderCreateReqVO.setCustomerId(customer.getId());
        airOrderCreateReqVO.setCustomerAgreementNo(SunstnUtils.getCustomerAgreementNo(rtResult.getRemark()));
        airOrderCreateReqVO.setCustomerAgreementType(StrUtil.isBlank(airOrderCreateReqVO.getCustomerAgreementNo()) ? CustomerAgreementTypeEnum.NORMAL.getType() : CustomerAgreementTypeEnum.CUSTOMER_AGREEMENT.getType());
        airOrderCreateReqVO.setSalesmanUserId(customer.getSalesmanUserId());
        airOrderCreateReqVO.setBookUserId(user.getId());
        airOrderCreateReqVO.setBookTime(LocalDateTime.now());
        airOrderCreateReqVO.setBookOffice(rtResult.getBookOffice());
        airOrderCreateReqVO.setNeedInvoice(customerProductSetting != null ? customerProductSetting.getNeedInvoice() : false);
        airOrderCreateReqVO.setMakeInvoiceType(customerProductSetting != null ? customerProductSetting.getMakeInvoiceType() : null);
        airOrderCreateReqVO.setInvoiceType(customerProductSetting != null ? customerProductSetting.getInvoiceType() : null);
        airOrderCreateReqVO.setRecycleInvoice(false);
        airOrderCreateReqVO.setDeliveryType(customerProductSetting != null ? customerProductSetting.getDeliveryType() : null);
        airOrderCreateReqVO.setDeliveryRemark(null);
        airOrderCreateReqVO.setDeliveryFee(BigDecimal.ZERO);
        airOrderCreateReqVO.setDeliveryContact(contactPassenger == null ? customer.getContact() : contactPassenger.getName());
        airOrderCreateReqVO.setDeliveryContactPhone(contactPassenger == null ? customer.getContactPhone() : contactPassenger.getMobile());
//            airOrderCreateReqVO.setDeliveryCityId();
//            airOrderCreateReqVO.setDeliveryAddress();
//            airOrderCreateReqVO.setDeliveryEmail();
//            airOrderCreateReqVO.setDeliveryUserId();
//            airOrderCreateReqVO.setDeliveryTime();
//        airOrderCreateReqVO.setFinallyReturnOrderType();
//        airOrderCreateReqVO.setFinallyReturnType();
//        airOrderCreateReqVO.setFinallyReturnCause();
//        airOrderCreateReqVO.setFinallyAdjustType();
        airOrderCreateReqVO.setSalePaySubjectId(customer.getPaySubjectId());
//        airOrderCreateReqVO.setSalePayAccount();
//        airOrderCreateReqVO.setSalePayOrderNo();
//        airOrderCreateReqVO.setSalePayTime();
//        airOrderCreateReqVO.setSalePayOnline();
//        airOrderCreateReqVO.setPurchaseId();
//        airOrderCreateReqVO.setPurchaseOrderNo();
//        airOrderCreateReqVO.setPurchasePaySubjectId();
//        airOrderCreateReqVO.setPurchasePayTypeId();
//        airOrderCreateReqVO.setPurchasePayAccount();
//        airOrderCreateReqVO.setPurchasePayOrderNo();
//        airOrderCreateReqVO.setPurchasePayTime();
//        airOrderCreateReqVO.setPurchasePayOnline();
        airOrderCreateReqVO.setContact(contactPassenger == null ? customer.getContact() : contactPassenger.getName());
//            airOrderCreateReqVO.setContactCardType();
//            airOrderCreateReqVO.setContactCardNo();
        airOrderCreateReqVO.setContactPhone(contactPassenger == null ? customer.getContactPhone() : contactPassenger.getMobile());
        airOrderCreateReqVO.setContactMobile(contactPassenger == null ? customer.getContactMobile() : contactPassenger.getMobile());
        airOrderCreateReqVO.setContactEmail(contactPassenger == null ? customer.getContactEmail() : contactPassenger.getEmail());
//        airOrderCreateReqVO.setRemark(rtResult.getRemark());

        // 行程信息
        List<AirOrderRouteCreateReqVO> routes = new ArrayList<>();
        int routeSerialNo = 1;
        for (AirRtRouteRespDTO route : rtResult.getRoutes()) {
            AirOrderRouteCreateReqVO airOrderRouteCreateReqVO = new AirOrderRouteCreateReqVO();
            airOrderRouteCreateReqVO.setSerialNo(routeSerialNo);
            airOrderRouteCreateReqVO.setAirlineNo(route.getAirlineNo());
            airOrderRouteCreateReqVO.setCarrierAirlineNo(route.getAirlineNo());
            airOrderRouteCreateReqVO.setFlightNo(route.getFlightNo());
            airOrderRouteCreateReqVO.setCabin(route.getCabin());
            airOrderRouteCreateReqVO.setDepart(route.getDepart());
            airOrderRouteCreateReqVO.setArrive(route.getArrive());
            airOrderRouteCreateReqVO.setFlightDate(route.getFlightDate());
//            airOrderRouteCreateReqVO.setArriveDate();
            airOrderRouteCreateReqVO.setDepartTime(route.getDepartTime());
            airOrderRouteCreateReqVO.setArriveTime(route.getArriveTime());
            airOrderRouteCreateReqVO.setDepartTerminal(route.getDepartTerminal());
            airOrderRouteCreateReqVO.setArriveTerminal(route.getArriveTerminal());
//            airOrderRouteCreateReqVO.setAirModel();
            airOrderRouteCreateReqVO.setHaveFood(false);
//            airOrderRouteCreateReqVO.setFoodType();
            airOrderRouteCreateReqVO.setStop(false);
//            airOrderRouteCreateReqVO.setStopAirportNo();
//            airOrderRouteCreateReqVO.setStopTerminal();
            airOrderRouteCreateReqVO.setShare(false);
            airOrderRouteCreateReqVO.setThrough(true);
//            airOrderRouteCreateReqVO.setPunctualityRate();
//            airOrderRouteCreateReqVO.setBaggageWeight();
            airOrderRouteCreateReqVO.setRouteStatus(route.getRouteStatus());
            routes.add(airOrderRouteCreateReqVO);
            routeSerialNo++;
        }
        airOrderCreateReqVO.setRoutes(routes);

        // 乘客信息
        List<AirOrderPassengerCreateReqVO> passengers = new ArrayList<>();
        int passengerSerialNo = 1;
        for (AirRtPassengerRespDTO passenger : rtResult.getPassengers()) {
            AirOrderPassengerCreateReqVO airOrderPassengerCreateReqVO = new AirOrderPassengerCreateReqVO();
            airOrderPassengerCreateReqVO.setSerialNo(passengerSerialNo);
            airOrderPassengerCreateReqVO.setType(passenger.getType());
            airOrderPassengerCreateReqVO.setCountryNo(passenger.getCountryNo());
            airOrderPassengerCreateReqVO.setName(passenger.getName());
            airOrderPassengerCreateReqVO.setSex(passenger.getSex());
            airOrderPassengerCreateReqVO.setCardType(passenger.getCardType());
            airOrderPassengerCreateReqVO.setCardNo(passenger.getCardNo());
            airOrderPassengerCreateReqVO.setCardValidDate(passenger.getCardValidDate());
            airOrderPassengerCreateReqVO.setCardIssuingCountryNo(passenger.getCardIssuingCountryNo());
            airOrderPassengerCreateReqVO.setBirthday(passenger.getBirthday());
            airOrderPassengerCreateReqVO.setHaveBaby(passenger.getHaveBaby());
//            airOrderPassengerCreateReqVO.setGuardianName();
            airOrderPassengerCreateReqVO.setMobile(passenger.getMobile());
//            airOrderPassengerCreateReqVO.setEmail();
            airOrderPassengerCreateReqVO.setSendSms(false);
            passengers.add(airOrderPassengerCreateReqVO);
            passengerSerialNo++;
        }
        airOrderCreateReqVO.setPassengers(passengers);

        // 价格信息
        // 机票服务费规则设置（默认取因公）
        AirServiceFeeRuleRespVO airServiceFeeRule = customer.getAirServiceFeeRule();
        AirServiceFeeRuleSettingTripTypeRespVO business = Optional.ofNullable(airServiceFeeRule).map(AirServiceFeeRuleRespVO::getBusiness).orElse(new AirServiceFeeRuleSettingTripTypeRespVO());
        AirServiceFeeRuleSettingRespVO airServiceFeeRuleSetting = isInternation ? business.getInternation() : business.getDomestic();
        // 初始默认0，兼容接口无价格
        AirRtPriceRespDTO lowestPrice = new AirRtPriceRespDTO();
        lowestPrice.setTicketPrice(BigDecimal.ZERO);
        lowestPrice.setAirportTax(BigDecimal.ZERO);
        lowestPrice.setOilTax(BigDecimal.ZERO);
        if (CollUtil.isNotEmpty(rtResult.getPrices())) {
            rtResult.getPrices().sort(Comparator.comparing(p -> p.getTicketPrice()));
            lowestPrice = rtResult.getPrices().get(0);
        }
        List<AirOrderPriceCreateReqVO> prices = new ArrayList<>();
        for (AirOrderRouteCreateReqVO route : routes) {
            for (AirOrderPassengerCreateReqVO passenger : passengers) {
                AirOrderPriceCreateReqVO airOrderPriceCreateReqVO = getAirOrderPriceCreateReqVO();
                airOrderPriceCreateReqVO.setRouteSerialNo(route.getSerialNo());
                airOrderPriceCreateReqVO.setPassengerSerialNo(passenger.getSerialNo());
                if (route.getSerialNo() == 1) {
                    // 价格写到第一航段
                    airOrderPriceCreateReqVO.setFareBasis(lowestPrice.getFareBasis());
                    // 销售
                    airOrderPriceCreateReqVO.setSaleTicketPrice(lowestPrice.getTicketPrice());
                    airOrderPriceCreateReqVO.setSalePrice(lowestPrice.getTicketPrice());
                    airOrderPriceCreateReqVO.setSaleAirportTax(lowestPrice.getAirportTax());
                    airOrderPriceCreateReqVO.setSaleOilTax(lowestPrice.getOilTax());
                    airOrderPriceCreateReqVO.setSaleTax(airOrderPriceCreateReqVO.getSaleAirportTax().add(airOrderPriceCreateReqVO.getSaleOilTax()));
                    airOrderPriceCreateReqVO.setSaleServiceFee(SunstnUtils.getSaleServiceFee(airServiceFeeRuleSetting, lowestPrice.getTicketPrice().add(lowestPrice.getAirportTax()).add(lowestPrice.getOilTax()), passenger.getType(), routes.size()));

                    // 采购
                    airOrderPriceCreateReqVO.setPurchaseTicketPrice(lowestPrice.getTicketPrice());
                    airOrderPriceCreateReqVO.setPurchasePrice(lowestPrice.getTicketPrice());
                    airOrderPriceCreateReqVO.setPurchaseAirportTax(lowestPrice.getAirportTax());
                    airOrderPriceCreateReqVO.setPurchaseOilTax(lowestPrice.getOilTax());
                    airOrderPriceCreateReqVO.setPurchaseTax(airOrderPriceCreateReqVO.getPurchaseAirportTax().add(airOrderPriceCreateReqVO.getPurchaseOilTax()));
                }
                prices.add(airOrderPriceCreateReqVO);
            }
        }
        airOrderCreateReqVO.setPrices(prices);
        orderId = TenantUtils.execute(tenantId, () -> airOrderService.createOrder(airOrderCreateReqVO));
        return orderId;
    }

    /**
     * 获得初始价格信息
     *
     * @return
     */
    private AirOrderPriceCreateReqVO getAirOrderPriceCreateReqVO() {
        AirOrderPriceCreateReqVO airOrderPriceCreateReqVO = new AirOrderPriceCreateReqVO();
        airOrderPriceCreateReqVO.setAirlineIssueNo(null);
        airOrderPriceCreateReqVO.setTicketNo(null);
        airOrderPriceCreateReqVO.setTicketLastNo(null);
        airOrderPriceCreateReqVO.setTicketVendingMachineNo(null);
        airOrderPriceCreateReqVO.setTicketStatus(null);
        airOrderPriceCreateReqVO.setSaleAdditionalFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleServiceFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleUpgradeFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleChangeFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleReturnFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleReturnFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleTicketPrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSalePrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleUsedPrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleAirportTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleUsedAirportTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleOilTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleUsedOilTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleUsedTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleAgencyFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleAgencyFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleBackRebateFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSaleBackRebateFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSalePrizePrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setSalePrizeTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseAdditionalFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseServiceFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseUpgradeFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseChangeFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseReturnFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseReturnFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseTicketPrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchasePrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseUsedPrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseAirportTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseUsedAirportTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseOilTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseUsedOilTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseUsedTax(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseAgencyFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseAgencyFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseBackRebateFeeRate(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchaseBackRebateFee(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchasePrizePrice(BigDecimal.ZERO);
        airOrderPriceCreateReqVO.setPurchasePrizeTax(BigDecimal.ZERO);
        return airOrderPriceCreateReqVO;
    }
}
